package org.shagin.jfin.data.model.domain;

import java.util.LinkedList;
import java.util.List;

import org.shagin.jfin.core.Debug;
import org.shagin.jfin.data.model.Account;
import org.shagin.jfin.data.model.Budget;
import org.shagin.jfin.data.model.ExpenseRule;
import org.shagin.jfin.data.model.IncomeRule;
import org.shagin.jfin.data.model.OperationCategoryLeaf;
import org.shagin.jfin.data.model.OperationRule;
import org.shagin.jfin.data.model.OperationRuleAction;
import org.shagin.jfin.data.model.TransferRule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The Class OperationRuleDomain.
 */
public class OperationRuleDomain extends BudgetDomain {

    private static final Logger log = LoggerFactory
            .getLogger(OperationRuleDomain.class);

    public static int INCOME = 1;
    public static int TRANSFER = 0;
    public static int EXPENSE = -1;

    private int operationTyp = EXPENSE;
    private List<OperationRule> rules = new LinkedList<OperationRule>();

    public OperationRuleDomain(Budget budget) {
        super(budget);
    }

    /**
     * Gets the rules.
     * 
     * @return the rules
     */
    public List<OperationRule> getRules() {
        return rules;
    }

    /**
     * Adds the.
     * 
     * @param ruleId the rule id
     * @param sourceAccount the source account
     * @param category the category
     * @param actions the actions
     * @return the operation rule
     */
    public OperationRule add(String ruleId, Account sourceAccount,
            OperationCategoryLeaf category, List<OperationRuleAction> actions) {
        OperationRule result = null;
        if (INCOME == operationTyp)
            result = addIncome(ruleId, sourceAccount, category, actions);
        else if (EXPENSE == operationTyp)
            result = addExpense(ruleId, sourceAccount, category, actions);
        return result;
    }

    /**
     * Adds the.
     * 
     * @param ruleId the rule id
     * @param sourceAccount the source account
     * @param destAccount the dest account
     * @param category the category
     * @param actions the actions
     * @return the operation rule
     */
    public OperationRule add(String ruleId, Account sourceAccount,
            Account destAccount, OperationCategoryLeaf category,
            List<OperationRuleAction> actions) {
        OperationRule result = null;
        if (TRANSFER == operationTyp)
            result = addTransfer(ruleId, sourceAccount, destAccount, category,
                    actions);
        return result;
    }

    /**
     * Adds the expense.
     * 
     * @param ruleId the rule id
     * @param sourceAccount the source account
     * @param category the category
     * @param actions the actions
     * @return the expense rule
     */
    private ExpenseRule addExpense(String ruleId, Account sourceAccount,
            OperationCategoryLeaf category, List<OperationRuleAction> actions) {
        ExpenseRule result = new ExpenseRule(ruleId, sourceAccount, category,
                actions, budget);
        add(result);
        return result;
    }

    /**
     * Adds the income.
     * 
     * @param ruleId the rule id
     * @param sourceAccount the source account
     * @param category the category
     * @param actions the actions
     * @return the income rule
     */
    private IncomeRule addIncome(String ruleId, Account sourceAccount,
            OperationCategoryLeaf category, List<OperationRuleAction> actions) {
        IncomeRule result = new IncomeRule(ruleId, sourceAccount, category,
                actions, budget);
        add(result);
        return result;
    }

    /**
     * Adds the transfer.
     * 
     * @param ruleId the rule id
     * @param sourceAccount the source account
     * @param destAccount the dest account
     * @param category the category
     * @param actions the actions
     * @return the transfer rule
     */
    private TransferRule addTransfer(String ruleId, Account sourceAccount,
            Account destAccount, OperationCategoryLeaf category,
            List<OperationRuleAction> actions) {
        TransferRule result = new TransferRule(ruleId, sourceAccount,
                destAccount, category, actions, budget);
        add(result);
        return result;
    }

    /**
     * Adds the.
     * 
     * @param rule the rule
     */
    public void add(OperationRule rule) {
        Debug.traceEnter(log);
        rules.add(rule);
    }

    /**
     * Incomes.
     */
    public void incomes() {
        operationTyp = INCOME;
    }

    /**
     * Expenses.
     */
    public void expenses() {
        operationTyp = EXPENSE;
    }

    /**
     * Trasfers.
     */
    public void trasfers() {
        operationTyp = TRANSFER;
    }

    /**
     * Gets the expenses.
     * 
     * @return the expenses
     */
    public List<OperationRule> getExpenses() {
        List<OperationRule> result = new LinkedList<OperationRule>();
        for (OperationRule rule : rules) {
            if (rule instanceof ExpenseRule)
                result.add(rule);
        }
        return result;
    }

    /**
     * Gets the incomes.
     * 
     * @return the incomes
     */
    public List<OperationRule> getIncomes() {
        List<OperationRule> result = new LinkedList<OperationRule>();
        for (OperationRule rule : rules) {
            if (rule instanceof IncomeRule)
                result.add(rule);
        }
        return result;
    }

    /**
     * Gets the trasfers.
     * 
     * @return the trasfers
     */
    public List<OperationRule> getTrasfers() {
        List<OperationRule> result = new LinkedList<OperationRule>();
        for (OperationRule rule : rules) {
            if (rule instanceof TransferRule)
                result.add(rule);
        }
        return result;
    }

    /**
     * Gets the operation typ.
     * 
     * @return the operation typ
     */
    public int getOperationTyp() {
        return operationTyp;
    }
}
